package com.zhoukai.business.service.license;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zhoukai.business.util.license.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

/**
 * author:zkai
 * date: 2024/1/31 15:18
 * description: 证书认证
 * version:1.0
 */
@Slf4j
@Component
public class LicenseVerify {

    @Value("${license.secretKey}")
    private String secretKey;

    /**
     * 校验License证书
     */
    // todo 需要加入缓存
    public boolean verify() {
        LicenseContent licenseContent = LicenseContentManager.instance();
        if (licenseContent == null || !checkSign(licenseContent, secretKey)) {
            throw new RuntimeException("证书异常");
        }
        checkTime(licenseContent);

        //校验IP地址
        LicenseContent.LicenseCheckModel licenseCheckModel = licenseContent.getLicenseCheckModel();
        if (licenseCheckModel != null) {
            //当前服务器真实的参数信息
            ServerInfo serverInfo = getServerInfos();

            if (!checkIpAddress(licenseCheckModel.getIpAddress(), serverInfo.getIpAddress())) {
                throw new RuntimeException("当前服务器的IP没在授权范围内");
            }

            //校验Mac地址
            if (!checkIpAddress(licenseCheckModel.getMacAddress(), serverInfo.getMacAddress())) {
                throw new RuntimeException("当前服务器的Mac地址没在授权范围内");
            }
            //校验主板序列号
            if (!checkSerial(licenseCheckModel.getMainBoardSerial(), serverInfo.getMainBoardSerial())) {
                throw new RuntimeException("当前服务器的主板序列号没在授权范围内");
            }
            //校验CPU序列号
            if (!checkSerial(licenseCheckModel.getCpuSerial(), serverInfo.getCpuSerial())) {
                throw new RuntimeException("当前服务器的CPU序列号没在授权范围内");
            }

        }
        return true;
    }

    /**
     * 获取当前服务器需要额外校验的License参数
     */
    private ServerInfo getServerInfos() {
        //操作系统类型
        String osName = System.getProperty("os.name").toLowerCase();
        AbstractServerInfos abstractServerInfos = null;

        //根据不同操作系统类型选择不同的数据获取方法
        if (osName.startsWith("windows")) {
            abstractServerInfos = new WindowsServerInfos();
        } else if (osName.startsWith("linux")) {
            abstractServerInfos = new LinuxServerInfos();
        } else {//其他服务器类型
            abstractServerInfos = new LinuxServerInfos();
        }

        return abstractServerInfos.getServerInfos();
    }


    private void checkTime(LicenseContent licenseContent) {
        Date now = new Date();
        Date issuedTime = DateUtil.parse(licenseContent.getIssuedTime(), "yyyy-MM-dd HH:mm:ss"); // 证书生效时间
        Date expiryTime = DateUtil.parse(licenseContent.getExpiryTime(), "yyyy-MM-dd HH:mm:ss"); // 证书失效时间
        if (issuedTime.after(now)) {
            throw new RuntimeException("证书当前还未失效,请联系系统管理员及时更新证书");
        }
        if (now.after(expiryTime)) {
            throw new RuntimeException("当前证书已失效,请联系系统管理员及时更新证书");
        }
    }

    /**
     * 校验证书签名信息
     */
    private boolean checkSign(LicenseContent licenseContent, String secretKey) {
        String licenseSign = null;
        try {
            licenseSign = EncryptUtil.decrypt(licenseContent.getSign(), secretKey);
        } catch (Exception e) {
            log.warn("证书签名异常", e);
            return false;
        }

        LicenseContent licenseContentRemoveSign = BeanUtil.copyProperties(licenseContent, LicenseContent.class);
        licenseContentRemoveSign.setSign(null);
        String jsonString = JSON.toJSONString(licenseContentRemoveSign, SerializerFeature.MapSortField);
        String sm3 = SmUtil.sm3(jsonString);
        if (!StrUtil.equals(licenseSign, sm3)) {
            log.warn("证书签名不一致");
            return false;
        }
        return true;

    }

    /**
     * 校验当前服务器的IP/Mac地址是否在可被允许的IP范围内<br/>
     * 如果存在IP在可被允许的IP/Mac地址范围内，则返回true
     */
    private boolean checkIpAddress(List<String> expectedList, List<String> serverList) {
        if (expectedList != null && expectedList.size() > 0) {
            if (serverList != null && serverList.size() > 0) {
                for (String expected : expectedList) {
                    if (serverList.contains(expected.trim())) {
                        return true;
                    }
                }
            }

            return false;
        } else {
            return true;
        }
    }

    /**
     * 校验当前服务器硬件（主板、CPU等）序列号是否在可允许范围内
     */
    private boolean checkSerial(String expectedSerial, String serverSerial) {
        if (StrUtil.isNotBlank(expectedSerial)) {
            if (StrUtil.isNotBlank(serverSerial)) {
                return expectedSerial.equals(serverSerial);
            }

            return false;
        } else {
            return true;
        }
    }

}
